From fce9983203a2acc609b9d8dca190fcaafdd42ffc Mon Sep 17 00:00:00 2001 From: Yehuda Katz Date: Thu, 19 Jun 2014 14:13:39 -0700 Subject: [PATCH] Add --verbose cause chain support --- libs/hammer.rs | 2 +- src/bin/cargo.rs | 6 ++--- src/cargo/lib.rs | 62 ++++++++++++++++++++++++++++++++++++------------ 3 files changed, 51 insertions(+), 19 deletions(-) diff --git a/libs/hammer.rs b/libs/hammer.rs index 673bbd958..9af78f5b1 160000 --- a/libs/hammer.rs +++ b/libs/hammer.rs @@ -1 +1 @@ -Subproject commit 673bbd95858fc0e6eae39d0d30a2781ba4c8d87e +Subproject commit 9af78f5b1fdfd09580758ec3b559c7704e6a5382 diff --git a/src/bin/cargo.rs b/src/bin/cargo.rs index 75608afbe..d700a876f 100644 --- a/src/bin/cargo.rs +++ b/src/bin/cargo.rs @@ -34,7 +34,7 @@ fn execute() { let (cmd, args) = match process(os::args()) { Ok((cmd, args)) => (cmd, args), - Err(err) => return handle_error(err) + Err(err) => return handle_error(err, false) }; if cmd == "config-for-key".to_str() { @@ -59,8 +59,8 @@ fn execute() { match command { Ok(ExitStatus(0)) => (), - Ok(ExitStatus(i)) | Ok(ExitSignal(i)) => handle_error(CliError::new("", i as uint)), - Err(_) => handle_error(CliError::new("No such subcommand", 127)) + Ok(ExitStatus(i)) | Ok(ExitSignal(i)) => handle_error(CliError::new("", i as uint), false), + Err(_) => handle_error(CliError::new("No such subcommand", 127), false) } } } diff --git a/src/cargo/lib.rs b/src/cargo/lib.rs index 61ce7ad09..106cb992c 100644 --- a/src/cargo/lib.rs +++ b/src/cargo/lib.rs @@ -19,8 +19,8 @@ extern crate hamcrest; use serialize::{Decoder,Encoder,Decodable,Encodable,json}; use std::io; -use hammer::{FlagDecoder,FlagConfig,HammerError}; -pub use util::{CliError, CliResult, human}; +use hammer::{FlagDecoder, FlagConfig, HammerError, FlagConfiguration}; +pub use util::{CargoError, CliError, CliResult, human}; macro_rules! some( ($e:expr) => ( @@ -53,30 +53,48 @@ pub struct NoFlags; impl FlagConfig for NoFlags {} +#[deriving(Decodable)] +pub struct GlobalFlags { + verbose: bool, + rest: Vec +} + +impl FlagConfig for GlobalFlags { + fn config(_: Option, c: FlagConfiguration) -> FlagConfiguration { + c.short("verbose", 'v') + } +} + pub fn execute_main<'a, T: RepresentsFlags, U: RepresentsJSON, V: Encodable, io::IoError>>(exec: fn(T, U) -> CliResult>) { - fn call<'a, T: RepresentsFlags, U: RepresentsJSON, V: Encodable, io::IoError>>(exec: fn(T, U) -> CliResult>) -> CliResult> { - let flags = try!(flags_from_args::()); + fn call<'a, T: RepresentsFlags, U: RepresentsJSON, V: Encodable, io::IoError>>(exec: fn(T, U) -> CliResult>, args: &[String]) -> CliResult> { + let flags = try!(flags_from_args::(args)); let json = try!(json_from_stdin::()); exec(flags, json) } - process_executed(call(exec)) + match global_flags() { + Err(e) => handle_error(e, true), + Ok(val) => process_executed(call(exec, val.rest.as_slice()), val) + } } pub fn execute_main_without_stdin<'a, T: RepresentsFlags, V: Encodable, io::IoError>>(exec: fn(T) -> CliResult>) { - fn call<'a, T: RepresentsFlags, V: Encodable, io::IoError>>(exec: fn(T) -> CliResult>) -> CliResult> { - let flags = try!(flags_from_args::()); + fn call<'a, T: RepresentsFlags, V: Encodable, io::IoError>>(exec: fn(T) -> CliResult>, args: &[String]) -> CliResult> { + let flags = try!(flags_from_args::(args)); exec(flags) } - process_executed(call(exec)); + match global_flags() { + Err(e) => handle_error(e, true), + Ok(val) => process_executed(call(exec, val.rest.as_slice()), val) + } } -pub fn process_executed<'a, T: Encodable, io::IoError>>(result: CliResult>) { +pub fn process_executed<'a, T: Encodable, io::IoError>>(result: CliResult>, flags: GlobalFlags) { match result { - Err(e) => handle_error(e), + Err(e) => handle_error(e, flags.verbose), Ok(encodable) => { encodable.map(|encodable| { let encoded = json::Encoder::str_encode(&encodable); @@ -86,23 +104,37 @@ pub fn process_executed<'a, T: Encodable, io::IoError>>(result } } -pub fn handle_error(err: CliError) { +pub fn handle_error(err: CliError, verbose: bool) { log!(4, "handle_error; err={}", err); let CliError { error, exit_code, .. } = err; let _ = write!(&mut std::io::stderr(), "{}", error); - // TODO: Cause chains - //detail.map(|d| write!(&mut std::io::stderr(), ":\n{}", d)); + + if verbose { + error.cause().map(handle_cause); + } std::os::set_exit_status(exit_code as int); } +fn handle_cause(err: &CargoError) { + println!("\nCaused by:"); + println!(" {}", err.description()); + + err.cause().map(handle_cause); +} + fn args() -> Vec { std::os::args() } -fn flags_from_args() -> CliResult { - let mut decoder = FlagDecoder::new::(args().tail()); +fn flags_from_args(args: &[String]) -> CliResult { + let mut decoder = FlagDecoder::new::(args); + Decodable::decode(&mut decoder).map_err(|e: HammerError| CliError::new(e.message, 1)) +} + +fn global_flags() -> CliResult { + let mut decoder = FlagDecoder::new::(args().tail()); Decodable::decode(&mut decoder).map_err(|e: HammerError| CliError::new(e.message, 1)) } -- 2.30.2